package myJs.user.workflow.featureSelection.uniAna

import com.softwaremill.quicklens._
import myJs.tool.Tool.messages

import scala.collection.immutable.SeqMap
import myJs.Implicits._
import myJs.cps._
import myJs.tool.Pojo._
import org.scalajs.dom.html
import myJs.myPkg.jquery._
import myJs.myPkg.reactHookForm._
import myJs.user.FeatureSelectionTool
import myJs.user.workflow.featureSelection.FeatureSelection
import myJs.user.workflow.featureSelection.oplsda.Oplsda
import shared.pojo.WorkflowMission.{EachUniAnaData, McInfo}
import upickle.default._
import japgolly.scalajs.react.vdom.all._
import japgolly.scalajs.react._
import japgolly.scalajs.react.React.Fragment
import japgolly.scalajs.react.util.EffectCatsEffect._
import myJs.myPkg.Hooks._
import cats.effect._
import myJs.Implicits._
import myJs.Utils._
import myJs.myPkg.MyReact

/** Created by yz on 3/11/2020
  */
object PostHocCp {

  case class Props(
      data: EachUniAnaData,
      dataChange: EachUniAnaData => SyncIO[Unit],
      allGroups: List[String],
      namePrefix: String
  ) {
    @inline def render: VdomElement = {
      Component(this)
    }
  }

  val Component = ScalaFnComponent[Props] { props =>
    val divRef = MyReact.createRef[html.Div]

    val useFieldArray = ReactHookForm.useFieldArray(
      UseFieldArrayOptions(
        name = s"${props.namePrefix}.mcInfos"
      )
    )

    object FTool {

      def execPostHocChange = (v: Boolean) => {
        SyncIO{} >> {
          val newData = props.data.modify(_.execPostHoc).setTo(v)
          props.dataChange(newData)
        }

      }

      def isInterChange = (v: String) => {
        SyncIO{} >>{
          val newData = props.data.modify(_.isInter).setTo(v)
          props.dataChange(newData)
        }

      }

      def groupChange(curI: Int) = (v: String) => {
        SyncIO{} >>{
          val newData = props.data.modify(_.mcInfos.index(curI).group).setTo(v)
          props.dataChange(newData)
        }

      }

      def pChange(curI: Int) = (v: String) => {
        SyncIO{} >> {
          val newData = props.data.modify(_.mcInfos.index(curI).`p.adj`).setTo(v)
          props.dataChange(newData)
        }
      }

      def log2FcChange(curI: Int) = (v: String) => {
        SyncIO{} >> {
          val newData = props.data.modify(_.mcInfos.index(curI).log2Fc).setTo(v)
          props.dataChange(newData)
        }
      }

      def removeModuleF(curI: Int) = {
        SyncIO {} >> {
          val newData = props.data.modify(_.mcInfos).using { x =>
            x.removed(curI)
          }
          useFieldArray.remove(curI)
          props.dataChange(newData)
        }
      }

      def add = {
        SyncIO{} >> {
          val mcInfo = McInfo(group = FTool.getGroupVs.headOption.getOrElse(""))
          val newData = props.data.modify(_.mcInfos).using { x =>
            x :+ mcInfo
          }
          useFieldArray.append(mcInfo)
          props.dataChange(newData)
        }
      }

      useEffect(
        {
          SyncIO{} >> {
            if (props.data.mcInfos.isEmpty && props.allGroups.nonEmpty) {
              FTool.add
            } else SyncIO.unit
          }
        },
        List(props.allGroups)
      )

      def getGroupVs = {
        props.allGroups
          .combinations(2)
          .map { groups =>
            val group1 = groups(0)
            val group2 = groups(1)
            s"${group1}-${group2}"
          }
          .toList
      }

    }

    val isMul = props.allGroups.size > 2
    val isIntersMap =
      SeqMap("T" -> messages("intersection"), "F" -> messages("union"))

    val groupMap = props.allGroups
      .combinations(2)
      .map { groups =>
        val group1 = groups(0)
        val group2 = groups(1)
        s"${group1}-${group2}"
      }
      .toList
      .optionMap
    val displayMod =
      if (props.data.execPostHoc) display.block else display.none
    val removeDisabled = props.data.mcInfos.size <= 1
    val postHocDisplayMod =
      if (isMul) display.block else display.none

    div(
      postHocDisplayMod,
      vRef := divRef,
      ToggleCp
        .Props(
          value = props.data.execPostHoc,
          label = messages("execPostHoc"),
          name = s"${props.namePrefix}.execPostHoc",
          valueChange = FTool.execPostHocChange
        )
        .render,
      div(
        displayMod,
        SelectCp
          .Props(
            value = props.data.isInter,
            label = messages("AllFilterConditionsTake"),
            name = s"${props.namePrefix}.isInter",
            optionMap = isIntersMap,
            onChange = FTool.isInterChange
          )
          .render,
        useFieldArray.fields.toList.zipWithIndex.toVdomArray { case (item, curI) =>
          val namePrefix = s"${props.namePrefix}.mcInfos.${curI}"
          val mcInfo = props.data.mcInfos.getOrElse(curI, McInfo(group = FTool.getGroupVs.headOption.getOrElse("")))
          fieldset(
            key := s"${item.id}",
            paddingRight := "5px",
            border := "1px solid silver",
            margin := "0 2px",
            borderRadius := "4px",
            className := "northbtn myEachSoft",
            MyToolCp
              .Props(
                removeModule = FTool.removeModuleF(curI),
                disabled = removeDisabled
              )
              .render,
            legend(s"${messages("FilteringConditions")}"),
            div(
              SelectCp
                .Props(
                  value = mcInfo.group,
                  label = messages("group"),
                  name = s"${namePrefix}.mcGroup",
                  optionMap = groupMap,
                  onChange = FTool.groupChange(curI)
                )
                .render,
              InputCp
                .Props(
                  value = mcInfo.`p.adj`,
                  label = messages("threshold"),
                  name = s"${namePrefix}.pValue",
                  onChange = FTool.pChange(curI),
                  questionInfo = messages("thresholdInfo"),
                  show = (isMul && props.data.execPostHoc)
                )
                .render,
              InputCp
                .Props(
                  value = mcInfo.log2Fc,
                  label = messages("log2FCCutoff"),
                  name = s"${namePrefix}.log2Fc",
                  onChange = FTool.log2FcChange(curI),
                  questionInfo = messages("log2FCCutoffInfo"),
                  show = (isMul && props.data.execPostHoc)
                )
                .render
            )
          )
        },
        button(
          width := "100%",
          marginTop := 5.px,
          `type` := "button",
          className := "btn btn-default addButton",
          onClick --> FTool.add,
          messages("addNewFilterCondition")
        )
      )
    )

  }

}
